package cn.edu.cug.cs.gtl.oi.render;

import cn.edu.cug.cs.gtl.common.Pair;
import cn.edu.cug.cs.gtl.protos.*;
import com.google.protobuf.InvalidProtocolBufferException;
import com.openinventor.inventor.SbColor;
import com.openinventor.inventor.SbVec3d;
import com.openinventor.inventor.nodes.*;
import com.openinventor.inventor.viewercomponents.awt.glcanvas.viewers.ViewerExaminer;

import java.util.ArrayList;
import java.util.List;

import static com.openinventor.inventor.nodes.SoIndexedFaceSet.SO_END_FACE_INDEX;
import static com.openinventor.inventor.nodes.SoIndexedLineSet.SO_END_LINE_INDEX;

public class Render {

    private SoNode sceneGraph = null;
    private ViewerExaminer viewer = null;

    //存放删除的结点，方便恢复时候使用
    private List<SoNode> soNodeList = new ArrayList<>();

    public Render() {
        viewer = new ViewerExaminer();
        sceneGraph = new SoSeparator();
    }

    public SoNode getSceneGraph() {
        return sceneGraph;
    }

    public void setSceneGraph(SoNode sceneGraph) {
        this.sceneGraph = sceneGraph;
        this.viewer.setSceneGraph(sceneGraph);
    }


    public ViewerExaminer getViewer() {
        return viewer;
    }

    public void setViewer(ViewerExaminer viewer) {
        this.viewer = viewer;
    }

    public void removeMapNode(Map map) {
        SoNode soNode = removeNode(getSceneGraph(), map);
        if (soNode != null)
            soNodeList.add(soNode);
    }

    public void removeLayerNode(Layer layer) {
        SoNode soNode = removeNode(getSceneGraph(), layer);
        if (soNode != null)
            soNodeList.add(soNode);
    }


    public void setVisible(Project project, boolean visible) {
        Pair<SoNode, SoNode> p = Render.findNode(sceneGraph, project);
        SoGroup separator = (SoGroup) p.getFirst();
        if (separator != null) {
            for (int i = 1; i < separator.getNumChildren(); ++i) {
                setProjectNodeVisible((SoGroup) separator.getChild(i), visible);
            }
        }
    }

    public void setVisible(Map map, boolean visible) {
        Pair<SoNode, SoNode> p = Render.findNode(sceneGraph, map);
        SoGroup separator = (SoGroup) p.getFirst();
        if (separator != null) {
            for (int i = 1; i < separator.getNumChildren(); ++i) {
                setLayerNodeVisible((SoGroup) separator.getChild(i), visible);
            }
        }
    }

    public void setVisible(Layer layer, boolean visible) {
        Pair<SoNode, SoNode> p = Render.findNode(sceneGraph, layer);
        SoGroup separator = (SoGroup) p.getFirst();
        setLayerNodeVisible(separator, visible);
    }

    /**
     * 显示和隐藏工程结点
     *
     * @param project
     * @param visible
     */
    private void setProjectNodeVisible(SoGroup project, boolean visible) {
        if (project != null) {
            for (int i = 1; i < project.getNumChildren(); ++i) {
                setMapNodeVisible((SoGroup) project.getChild(i), visible);
            }
        }
    }

    /**
     * 显示和隐藏图幅结点
     *
     * @param map
     * @param visible
     */
    private void setMapNodeVisible(SoGroup map, boolean visible) {
        if (map != null) {
            for (int i = 1; i < map.getNumChildren(); ++i) {
                setLayerNodeVisible((SoGroup) map.getChild(i), visible);
            }
        }
    }

    /**
     * 显示和隐藏图层结点
     *
     * @param layer
     * @param visible
     */
    private void setLayerNodeVisible(SoGroup layer, boolean visible) {
        if (layer != null) {
            for (int i = 1; i < layer.getNumChildren(); ++i) {
                if (visible) {
                    SoGroup g = (SoGroup) layer.getChild(i);
                    g.replaceChild(0, new SoDrawStyle());
                } else {
                    SoGroup g = (SoGroup) layer.getChild(i);
                    SoDrawStyle soDrawStyle = new SoDrawStyle();
                    soDrawStyle.style.setValue(SoDrawStyle.Styles.INVISIBLE);
                    g.replaceChild(0, soDrawStyle);
                }
            }
        }
    }

    private static void findNode(SoNode sceneGraph, SoNode parent, String nodeName, Pair<SoNode, SoNode> result) {
        if (sceneGraph == null)
            return;
        if (sceneGraph.getName().equals(nodeName)) {
            result.setKey(sceneGraph);
            result.setValue(parent);
            return;
        } else {
            if (sceneGraph instanceof SoGroup) {
                int c = ((SoGroup) sceneGraph).getNumChildren();
                for (int i = 0; i < c; ++i) {
                    if ((((SoGroup) sceneGraph).getChild(i).equals(nodeName))) {
                        result.setKey(((SoGroup) sceneGraph).getChild(i));
                        result.setValue(sceneGraph);
                        return;
                    }
                }
                for (int i = 0; i < c; ++i) {
                    findNode(((SoGroup) sceneGraph).getChild(i), sceneGraph, nodeName, result);
                }
            }
        }
    }

    public static Pair<SoNode, SoNode> findNode(SoNode sceneGraph, Project project) {
        Pair<SoNode, SoNode> p = new Pair<>();
        String nodeName = nodeName(project);
        findNode(sceneGraph, null, nodeName, p);
        return p;
    }

    public static Pair<SoNode, SoNode> findNode(SoNode sceneGraph, Map map) {
        Pair<SoNode, SoNode> p = new Pair<>();
        String nodeName = nodeName(map);
        findNode(sceneGraph, null, nodeName, p);
        return p;
    }

    public static Pair<SoNode, SoNode> findNode(SoNode sceneGraph, Layer layer) {
        Pair<SoNode, SoNode> p = new Pair<>();
        String nodeName = nodeName(layer);
        findNode(sceneGraph, null, nodeName, p);
        return p;
    }

    public static SoNode removeNode(SoNode sceneGraph, Project project) {
        SoSeparator root = (SoSeparator) sceneGraph;
        return root;
    }

    public static SoNode removeNode(SoNode sceneGraph, Map map) {
        Pair<SoNode, SoNode> p = findNode(sceneGraph, map);
        if (p != null) {
            if (p.getFirst() != null) {
                if (p.getSecond() != null) {
                    SoGroup g = (SoGroup) p.getSecond();
                    g.removeChild(p.getFirst());
                    return p.getFirst();
                }
            }
        }
        return null;
    }

    public static SoNode removeNode(SoNode sceneGraph, Layer layer) {
        Pair<SoNode, SoNode> p = findNode(sceneGraph, layer);
        if (p != null) {
            if (p.getFirst() != null) {
                if (p.getSecond() != null) {
                    SoGroup g = (SoGroup) p.getSecond();
                    g.removeChild(p.getFirst());
                    return p.getFirst();
                }
            }
        }
        return null;
    }

    public static String nodeName(Project project) {
        return "Project";
    }

    public static String nodeName(Map map) {
        return "MAP-"
                + Long.valueOf(map.getIdentifier().getExtent()).toString()
                + "-"
                + Long.valueOf(map.getIdentifier().getData()).toString();
    }

    public static String nodeName(Layer layer) {
        return "LAYER-"
                + Long.valueOf(layer.getIdentifier().getExtent()).toString()
                + "-"
                + Long.valueOf(layer.getIdentifier().getData()).toString();
    }

    public static String nodeName(Geometry geometry) {
        return "GEOMETRY-"
                + Long.valueOf(geometry.getIdentifier().getExtent()).toString()
                + "-"
                + Long.valueOf(geometry.getIdentifier().getData()).toString();
    }

    public static SoNode createProjectNode(Project project) throws InvalidProtocolBufferException {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(project));
        int mapSize = project.getMapCount();
        for (int i = 0; i < mapSize; ++i) {
            SoNode soNode = createMapNode(project.getMap(i));
            if (soNode != null)
                root.addChild(soNode);
        }
        return root;
    }

    public static SoNode createMapNode(Map map) throws InvalidProtocolBufferException {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(map));
        int layerSize = map.getLayerCount();
        for (int i = 0; i < layerSize; ++i) {
            SoNode soNode = createLayerNode(map.getLayer(i));
            if (soNode != null)
                root.addChild(soNode);
        }
        return root;
    }

    public static SoNode createLayerNode(Layer layer) throws InvalidProtocolBufferException {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(layer));
        int geometrySize = layer.getGeometryCount();
        for (int i = 0; i < geometrySize; ++i) {
            SoNode soNode = createGeometryNode(layer.getGeometry(i));
            if (soNode != null)
                root.addChild(soNode);
        }
        return root;
    }

    public static SoNode createGeometryNode(Geometry geometry) throws InvalidProtocolBufferException {
        GeometryType geometryType = geometry.getType();

        switch (geometryType) {
            case POINT3D: {
                Point3D shape = geometry.getShape().unpack(Point3D.class);
                return createPoint3DNode(geometry, shape);
            }
            case LINESTRING3D: {
                LineString3D shape = geometry.getShape().unpack(LineString3D.class);
                return createLineString3DNode(geometry, shape);
            }
            case POLYLINE3D: {
                Polyline3D shape = geometry.getShape().unpack(Polyline3D.class);
                return createPolyline3DNode(geometry, shape);
            }
            case POLYGONALMESH3D: {
                PolygonalMesh3D shape = geometry.getShape().unpack(PolygonalMesh3D.class);
                return createPolygonalMesh3DNode(geometry, shape);
            }
            case POLYHEDRALMESH3D: {
                PolyhedralMesh3D shape = geometry.getShape().unpack(PolyhedralMesh3D.class);
                return createPolyhedralMesh3D(geometry, shape);
            }
            default: {
                System.out.println("不支持的几何类型");
                return null;
            }
        }
    }

    private static SoNode createPoint3DNode(Geometry geometry, Point3D point3D) {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));

        //material
        {
            List<Color4f> color4fs = null;//polyline3D.getColorList();
            if (color4fs != null && color4fs.isEmpty() == false) {
                int size = color4fs.size();
                SbColor[] sbColors = new SbColor[size];
                float[] rgba = new float[3];
                for (int i = 0; i < size; ++i) {
                    rgba[0] = color4fs.get(i).getR();
                    rgba[1] = color4fs.get(i).getG();
                    rgba[2] = color4fs.get(i).getB();
                    //rgba[3] = color4fs.get(i).getA();
                    sbColors[i] = new SbColor(rgba);
                }
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.PER_VERTEX_INDEXED);
            } else {
                Color4f color4f = geometry.getColor();
                SbColor[] sbColors = new SbColor[1];
                sbColors[0] = new SbColor(color4f.getR(), color4f.getG(), color4f.getB());
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.OVERALL);
            }

        }
        //coordinates
        {
            SoCoordinate3 coordinate3 = new SoCoordinate3();
            int vertexCount = 1;
            SbVec3d[] vec3ds = new SbVec3d[vertexCount];
            vec3ds[0] = new SbVec3d(point3D.getLocation().getX(), point3D.getLocation().getY(), point3D.getLocation().getZ());
            coordinate3.point.setValues(0, vec3ds);
            root.addChild(coordinate3);
        }
        {
            //indexes
            int vertexCount = 1;
            int[] idxes = new int[vertexCount + 1];
            int i = 0;
            for (i = 0; i < vertexCount; ++i) {
                idxes[i] = i;
            }
            //idxes[i]=SO_END_POINT_SET_INDEX;
            SoIndexedPointSet lineSet = new SoIndexedPointSet();
            lineSet.coordIndex.setValues(0, idxes);
            root.addChild(lineSet);

            SoCube soCube = new SoCube();
//            soCube.width.setValue(0.1f);
            SoTranslation soTranslation = new SoTranslation();
            soTranslation.translation.setValue(
                    Double.valueOf(point3D.getLocation().getX()).floatValue(),
                    Double.valueOf(point3D.getLocation().getY()).floatValue(),
                    Double.valueOf(point3D.getLocation().getZ()).floatValue());
            SoScale soScale = new SoScale();
            soScale.scaleFactor.setValue(0.01f, 0.01f, 0.01f);
            root.addChild(soTranslation);
            root.addChild(soScale);
            root.addChild(soCube);
        }
        return root;
    }


    private static SoNode createPolyline3DNode(Geometry geometry, Polyline3D polyline3D) {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));
        //material
        {
            List<Color4f> color4fs = polyline3D.getColorList();
            if (color4fs != null && color4fs.isEmpty() == false) {
                int size = color4fs.size();
                SbColor[] sbColors = new SbColor[size];
                float[] rgba = new float[3];
                for (int i = 0; i < size; ++i) {
                    rgba[0] = color4fs.get(i).getR();
                    rgba[1] = color4fs.get(i).getG();
                    rgba[2] = color4fs.get(i).getB();
                    //rgba[3] = color4fs.get(i).getA();
                    sbColors[i] = new SbColor(rgba);
                }
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.PER_VERTEX_INDEXED);
            } else {
                Color4f color4f = geometry.getColor();
                SbColor[] sbColors = new SbColor[1];
                sbColors[0] = new SbColor(color4f.getR(), color4f.getG(), color4f.getB());
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.OVERALL);
            }

        }
        //coordinates
        {
            SoCoordinate3 coordinate3 = new SoCoordinate3();
            int vertexCount = polyline3D.getVertexCount();
            SbVec3d[] vec3ds = new SbVec3d[vertexCount];
            int i = 0;
            for (Vertex3d v : polyline3D.getVertexList()) {
                vec3ds[i] = new SbVec3d(v.getX(), v.getY(), v.getZ());
                ++i;
            }
            coordinate3.point.setValues(0, vec3ds);
            root.addChild(coordinate3);
        }
        {
            //indexes
            ArrayList<Integer> idx = new ArrayList<>();
            List<Integer> list = polyline3D.getIndexList();
            int i = 0;
            if (list.isEmpty() == false) {
                int lineSize = list.get(i);
                ++i;
                for (int k = 0; k < lineSize; ++k) {
                    int vertexSize = list.get(i);
                    ++i;
                    for (int j = 0; j < vertexSize; ++j) {
                        idx.add(list.get(i));
                        ++i;
                    }
                    idx.add(SO_END_LINE_INDEX);
                }
            }
            int size = idx.size();
            int[] idxes = new int[size];
            for (i = 0; i < size; ++i) {
                idxes[i] = idx.get(i).intValue();
            }
            SoIndexedLineSet lineSet = new SoIndexedLineSet();
            lineSet.coordIndex.setValues(0, idxes);
            root.addChild(lineSet);
        }
        return root;
    }


    private static SoNode createLineString3DNode(Geometry geometry, LineString3D polyline3D) {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));
        //material
        {
            List<Color4f> color4fs = null;//polyline3D.getColorList();
            if (color4fs != null && color4fs.isEmpty() == false) {
                int size = color4fs.size();
                SbColor[] sbColors = new SbColor[size];
                float[] rgba = new float[3];
                for (int i = 0; i < size; ++i) {
                    rgba[0] = color4fs.get(i).getR();
                    rgba[1] = color4fs.get(i).getG();
                    rgba[2] = color4fs.get(i).getB();
                    //rgba[3] = color4fs.get(i).getA();
                    sbColors[i] = new SbColor(rgba);
                }
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.PER_VERTEX_INDEXED);
            } else {
                Color4f color4f = geometry.getColor();
                SbColor[] sbColors = new SbColor[1];
                sbColors[0] = new SbColor(color4f.getR(), color4f.getG(), color4f.getB());
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.OVERALL);
            }

        }
        //coordinates
        {
            SoCoordinate3 coordinate3 = new SoCoordinate3();
            int vertexCount = polyline3D.getVertexCount();
            SbVec3d[] vec3ds = new SbVec3d[vertexCount];
            int i = 0;
            for (Vertex3d v : polyline3D.getVertexList()) {
                vec3ds[i] = new SbVec3d(v.getX(), v.getY(), v.getZ());
                ++i;
            }
            coordinate3.point.setValues(0, vec3ds);
            root.addChild(coordinate3);
        }
        {
            //indexes
            int vertexCount = polyline3D.getVertexCount();
            int[] idxes = new int[vertexCount + 1];
            int i = 0;
            for (i = 0; i < vertexCount; ++i) {
                idxes[i] = i;
            }
            idxes[i] = SO_END_LINE_INDEX;
            SoIndexedLineSet lineSet = new SoIndexedLineSet();
            lineSet.coordIndex.setValues(0, idxes);
            root.addChild(lineSet);
        }
        return root;
    }

    private static SoNode createPolygonalMesh3DNode(Geometry geometry, PolygonalMesh3D polygonalMesh3D) {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));
        //material
        {
            List<Color4f> color4fs = polygonalMesh3D.getColorList();
            if (color4fs != null && color4fs.isEmpty() == false) {
                int size = color4fs.size();
                SbColor[] sbColors = new SbColor[size];
                float[] rgba = new float[3];
                for (int i = 0; i < size; ++i) {
                    rgba[0] = color4fs.get(i).getR();
                    rgba[1] = color4fs.get(i).getG();
                    rgba[2] = color4fs.get(i).getB();
                    //rgba[3] = color4fs.get(i).getA();
                    sbColors[i] = new SbColor(rgba);
                }
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.PER_VERTEX_INDEXED);
            } else {
                Color4f color4f = geometry.getColor();
                SbColor[] sbColors = new SbColor[1];
                sbColors[0] = new SbColor(color4f.getR(), color4f.getG(), color4f.getB());
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.OVERALL);
            }
        }
        //coordinates
        {
            SoCoordinate3 coordinate3 = new SoCoordinate3();
            int vertexCount = polygonalMesh3D.getVertexCount();
            SbVec3d[] vec3ds = new SbVec3d[vertexCount];
            int i = 0;
            List<Vertex3d> vertex3dList = polygonalMesh3D.getVertexList();
            for (Vertex3d v : vertex3dList) {
                vec3ds[i] = new SbVec3d(v.getX(), v.getY(), v.getZ());
                ++i;
            }
            coordinate3.point.setValues(0, vec3ds);
            root.addChild(coordinate3);
        }
        {
            //indexes
            ArrayList<Integer> idx = new ArrayList<>();
            List<Integer> list = polygonalMesh3D.getIndexList();
            int i = 0;
            if (list.isEmpty() == false) {
                int faceSize = list.get(i);
                ++i;
                for (int k = 0; k < faceSize; ++k) {
                    int vertexSize = list.get(i);
                    ++i;
                    for (int j = 0; j < vertexSize; ++j) {
                        idx.add(list.get(i));
                        ++i;
                    }
                    idx.add(SO_END_FACE_INDEX);
                }
            }
            int size = idx.size();
            int[] idxes = new int[size];
            for (i = 0; i < size; ++i) {
                idxes[i] = idx.get(i).intValue();
            }
            SoIndexedFaceSet faceSet = new SoIndexedFaceSet();
            faceSet.coordIndex.setValues(0, idxes);
            root.addChild(faceSet);
        }
        return root;
    }

    private static SoNode createPolyhedralMesh3D(Geometry geometry, PolyhedralMesh3D polyhedralMesh3D) {
        SoSeparator root = new SoSeparator();
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        root.addChild(soDrawStyle);
        root.setName(nodeName(geometry));
        //material
        {
            List<Color4f> color4fs = polyhedralMesh3D.getColorList();
            if (color4fs != null && color4fs.isEmpty() == false) {
                int size = color4fs.size();
                SbColor[] sbColors = new SbColor[size];
                float[] rgba = new float[3];
                for (int i = 0; i < size; ++i) {
                    rgba[0] = color4fs.get(i).getR();
                    rgba[1] = color4fs.get(i).getG();
                    rgba[2] = color4fs.get(i).getB();
                    //rgba[3] = color4fs.get(i).getA();
                    sbColors[i] = new SbColor(rgba);
                }
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.PER_VERTEX_INDEXED);
            } else {
                Color4f color4f = geometry.getColor();
                SbColor[] sbColors = new SbColor[1];
                sbColors[0] = new SbColor(color4f.getR(), color4f.getG(), color4f.getB());
                SoMaterial material = new SoMaterial();
                material.diffuseColor.setValues(0, sbColors);
                root.addChild(material);

                //material binding
                SoMaterialBinding materialBinding = new SoMaterialBinding();
                materialBinding.value.setValue(SoMaterialBinding.Bindings.OVERALL);
            }

        }

        //coordinates
        {
            SoCoordinate3 coordinate3 = new SoCoordinate3();
            int vertexCount = polyhedralMesh3D.getVertexCount();
            SbVec3d[] vec3ds = new SbVec3d[vertexCount];
            int i = 0;
            List<Vertex3d> vertex3dList = polyhedralMesh3D.getVertexList();
            for (Vertex3d v : vertex3dList) {
                vec3ds[i] = new SbVec3d(v.getX(), v.getY(), v.getZ());
                ++i;
            }
            coordinate3.point.setValues(0, vec3ds);
            root.addChild(coordinate3);
        }

        //indexes
        {
            ArrayList<Integer> idx = new ArrayList<>();
            List<Integer> list = polyhedralMesh3D.getIndexList();
            int i = 0;
            if (list.isEmpty() == false) {
                int solidSize = list.get(i);
                ++i;
                for (int l = 0; l < solidSize; ++l) {
                    int faceSize = list.get(i);
                    ++i;
                    for (int k = 0; k < faceSize; ++k) {
                        int vertexSize = list.get(i);
                        ++i;
                        for (int j = 0; j < vertexSize; ++j) {
                            idx.add(list.get(i));
                            ++i;
                        }
                        idx.add(SO_END_FACE_INDEX);
                    }
                }
            }
            int size = idx.size();
            int[] idxes = new int[size];
            for (i = 0; i < size; ++i) {
                idxes[i] = idx.get(i).intValue();
            }
            SoIndexedFaceSet faceSet = new SoIndexedFaceSet();
            faceSet.coordIndex.setValues(0, idxes);
            root.addChild(faceSet);
        }

        return root;
    }
}
